from django.shortcuts import render, redirect
from django.http import JsonResponse, HttpResponseRedirect
from rest_framework.views import APIView
import random
import string
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import base64
from utils.redis_client import get_redis_client
from utils.ronglianyun_sms import send_sms_code as ronglian_send_sms_code
from .models import User, ThirdPartyAccount
from utils.jwttool import jwtTool
import os
import requests
import time
import uuid
from rest_framework.response import Response

redis_client = get_redis_client()

class CaptchaView(APIView):
    def get(self, request):
        """生成彩色图片验证码，带干扰线和点"""
        code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
        key = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
        redis_client.setex(f'captcha:{key}', 300, code.upper())  # 5分钟有效

        def get_random_color():
            return (random.randint(32, 127), random.randint(32, 127), random.randint(32, 127))

        def get_random_line(draw, width, height):
            for _ in range(5):
                x1 = random.randint(0, width)
                y1 = random.randint(0, height)
                x2 = random.randint(0, width)
                y2 = random.randint(0, height)
                draw.line(((x1, y1), (x2, y2)), fill=get_random_color())

        def get_random_point(draw, width, height):
            for _ in range(30):
                x = random.randint(0, width)
                y = random.randint(0, height)
                draw.point((x, y), fill=get_random_color())

        width, height = 160, 60
        img = Image.new('RGB', (width, height), color=(255, 255, 255))
        draw = ImageDraw.Draw(img)
        # 字体路径自动适配
        font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
        if not os.path.exists(font_path):
            font_path = "C:/Windows/Fonts/Arial.ttf"
        font = ImageFont.truetype(font_path, 36)
        # 绘制验证码字符（每个字符不同颜色，居中分布）
        for i, char in enumerate(code):
            x = 20 + i * 30
            y = 10
            draw.text((x, y), char, font=font, fill=(random.randint(32, 127), random.randint(32, 127), random.randint(32, 127)))
        # 增加更多干扰线
        for _ in range(8):
            x1 = random.randint(0, width)
            y1 = random.randint(0, height)
            x2 = random.randint(0, width)
            y2 = random.randint(0, height)
            draw.line(((x1, y1), (x2, y2)), fill=(random.randint(32, 127), random.randint(32, 127), random.randint(32, 127)), width=2)
        # 增加更多干扰点
        for _ in range(60):
            x = random.randint(0, width)
            y = random.randint(0, height)
            draw.point((x, y), fill=(random.randint(32, 127), random.randint(32, 127), random.randint(32, 127)))
        # 可选：加模糊滤镜
        # img = img.filter(ImageFilter.BLUR)
        buffer = BytesIO()
        img.save(buffer, format='PNG')
        img_str = base64.b64encode(buffer.getvalue()).decode()
        return JsonResponse({'captcha_key': key, 'captcha_img': img_str})

class SendSMSCodeView(APIView):
    def post(self, request):
        """校验图片验证码，正确则发送短信验证码（容联云）"""
        if request.method != 'POST':
            return JsonResponse({'error': 'POST required'}, status=405)
        data = request.data
        phone = data.get('phone')
        captcha_key = data.get('captcha_key')
        captcha_code = data.get('captcha_code', '').upper()
        if not (phone and captcha_key and captcha_code):
            return JsonResponse({'error': '参数不全'}, status=400)
        real_code = redis_client.get(f'captcha:{captcha_key}')
        if not real_code or real_code != captcha_code:
            return JsonResponse({'error': '图片验证码错误'}, status=400)
        sms_code = ''.join(random.choices(string.digits, k=4))
        redis_client.setex(f'sms:{phone}', 300, sms_code)
        try:
            resp = ronglian_send_sms_code(phone, sms_code, '5')
            if resp.get('statusCode') == '000000':
                return JsonResponse({'msg': '短信验证码已发送'})
            else:
                return JsonResponse({'error': '短信发送失败', 'detail': resp}, status=500)
        except Exception as e:
            return JsonResponse({'error': '短信服务异常', 'detail': str(e)}, status=500)

class SMSLoginView(APIView):
    def post(self, request):
        """短信验证码登录，未注册手机号自动注册"""
        if request.method != 'POST':
            return JsonResponse({'error': 'POST required'}, status=405)
        data = request.data
        phone = data.get('phone')
        sms_code = data.get('sms_code')
        if not (phone and sms_code):
            return JsonResponse({'error': '参数不全'}, status=400)
        real_sms_code = redis_client.get(f'sms:{phone}')
        if not real_sms_code or real_sms_code != sms_code:
            return JsonResponse({'error': '短信验证码错误'}, status=400)
        # 自动注册：查找或创建用户
        user, created = User.objects.get_or_create(phone=phone)
        token = jwtTool.get_token(user.id)
        return JsonResponse({'msg': '登录成功', 'token': token, 'userid': user.id})

class TestSMSLoginView(APIView):
    """
    测试用：写死验证码的短信登录接口，方便开发测试。
    """
    def post(self, request):
        phone = request.data.get('phone')
        sms_code = request.data.get('sms_code')
        # 设定写死的测试手机号和验证码
        TEST_PHONE = '13800000000'
        TEST_CODE = '8888'
        if phone == TEST_PHONE and sms_code == TEST_CODE:
            return JsonResponse({'msg': '测试登录成功'})
        return JsonResponse({'error': '测试账号或验证码错误'}, status=400)

class DingTalkCallbackView(APIView):
    """
    钉钉OAuth2.0回调接口，处理钉钉第三方登录
    """
    def get(self, request):
        # 获取code参数，兼容code和authCode
        code = request.GET.get('code')
        print(code)
        if not code:
            return HttpResponseRedirect('/?error=钉钉授权失败')
        # 用code换access_token
        data = {
            "clientId": "dingojddzaky0mtl8lwo",  # 客户端ID
            "clientSecret": "CmTHX8kUh9Y6JAUgyjDwsCr5hUZ03UFqdOUgSDReRhuZ9fsDa1qTZOwvmqQxbruu",  # 客户端密钥
            "code": code,  # 授权码
            "grantType": "authorization_code"  # 授权类型
        }
        resp = requests.post('https://api.dingtalk.com/v1.0/oauth2/userAccessToken', json=data).json()
        print('换token返回:', resp)
        access_token = resp.get('accessToken')
        if not access_token:
            # 返回钉钉原始错误信息，便于前端提示
            return Response({'code': resp.get('code', 500), 'msg': resp.get('message', '获取access_token失败')}, status=400)
        # 获取用户信息
        headers = {"x-acs-dingtalk-access-token": access_token}
        userinfo = requests.get('https://api.dingtalk.com/v1.0/contact/users/me', headers=headers).json()
        print('用户信息:', userinfo)
        if 'code' in userinfo and userinfo['code'] != '0':
            return Response({'code': userinfo.get('code', 500), 'msg': userinfo.get('message', '获取用户信息失败')}, status=400)
        # 获取用户id、手机号
        uid = userinfo.get('openId')
        phone = userinfo.get('mobile')
        unionid = userinfo.get('unionId')
        avatar_url = userinfo.get('avatarUrl')
        nickname = userinfo.get('nick')  # 获取昵称
        print('uid', uid)
        print('手机号:', phone)
        # 查找或创建本地用户（确保写入库）
        user, created = User.objects.get_or_create(phone=phone)
        # 查找或创建第三方账号绑定
        tp, tp_created = ThirdPartyAccount.objects.get_or_create(
            provider='dingtalk',
            openid=uid,
            defaults={
                'user': user,
                'unionid': unionid,
                'extra_data': userinfo,
                'avatar_url': avatar_url,
                'nickname': nickname,
            }
        )
        if not tp_created:
            tp.extra_data = userinfo
            tp.unionid = unionid
            tp.user = user
            tp.avatar_url = avatar_url  # 头像每次都更新
            # 不自动覆盖tp.nickname
            tp.save()
        # 生成本地token
        token = jwtTool.get_token(user.id)
        # 拼接前端首页URL，带上token和userid
        frontend_url = f"http://localhost:5173/community?token={token}&userid={user.id}"
        return HttpResponseRedirect(frontend_url)


class DDGetUrl(APIView):
    def get(self, request):
        # 生成随机状态码，防止CSRF攻击
        state = str(uuid.uuid4())
        request.session['dingtalk_state'] = state
        # 构建钉钉授权URL
        redirect_uri = "http://127.0.0.1:8000/login/ddcallback/"  # 回调地址，需和钉钉后台一致
        DINGTALK_APPID = 'dingojddzaky0mtl8lwo'
        url = (
            f"https://login.dingtalk.com/oauth2/auth"
            f"?redirect_uri={redirect_uri}"
            f"&response_type=code"
            f"&client_id={DINGTALK_APPID}"
            f"&scope=openid+Contact.User.Read"
            f"&state={state}"
            f"&prompt=consent"
        )
        return Response({"code": 200, "msg": "获取成功！", "url": url})

def get_thirdparty_avatar(request):
    openid = request.GET.get('openid')
    if not openid:
        return JsonResponse({'error': '缺少openid参数'}, status=400)
    try:
        account = ThirdPartyAccount.objects.get(openid=openid)
        return JsonResponse({'avatar_url': account.avatar_url})
    except ThirdPartyAccount.DoesNotExist:
        return JsonResponse({'error': '未找到该用户'}, status=404)

def get_thirdparty_avatar_by_userid(request):
    """通过userid获取第三方头像和昵称（只返回nickname字段）"""
    userid = request.GET.get('userid')
    if not userid:
        return JsonResponse({'error': '缺少userid参数'}, status=400)
    try:
        user = User.objects.get(id=userid)
        account = ThirdPartyAccount.objects.get(user=user, provider='dingtalk')
        return JsonResponse({
            'avatar_url': account.avatar_url,
            'nickname': account.nickname  # 只返回nickname字段
        })
    except User.DoesNotExist:
        return JsonResponse({'error': '用户不存在'}, status=404)
    except ThirdPartyAccount.DoesNotExist:
        return JsonResponse({'error': '未找到第三方账号绑定'}, status=404)


from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
import random


class TestWebsocket(APIView):
    def get(self, request):
        # 获取信息
        # 查询数据库对比

        # update = AllDataConsumersUpdate()
        # update.all_active_visit_data()
        channel_layer = get_channel_layer()
        send_data = {"error": "1号大鹏温度太高", 'namelist': ['1001', '1002'],
                     'valuelist': [random.randint(10, 100), random.randint(100, 200)]}
        # send_data = {"name":rand.randint(1,100)}
        async_to_sync(channel_layer.group_send)(
            '1',  # 房间组名
            {
                'type': 'send_to_chrome',  # 消费者中处理的函数
                'data': send_data
            }
        )
        return JsonResponse({"code": 200, "msg": "更新数据成功"})
